import React from 'react';
import { Modal,Tree } from 'antd';
// import { FormInstance } from 'antd/es/form/Form';
import type { DataNode, TreeProps } from 'antd/es/tree';
import isEqual from 'lodash/isEqual';
import memoizeOne from 'memoize-one';
import { FormModalProps } from '@/models/FormModal';
import { FlagEnum } from '@/models/common';
import { AuthTreeData, MenuTreeItem, GrantKey } from '../data';

type GrantAuthProps<T> = FormModalProps<T> & {
  flag: FlagEnum;
}

type CheckedKeys = React.Key[] | {
  checked: React.Key[];
  halfChecked: React.Key[];
}

type GrantAuthState = {
  expandedKeys: React.Key[];
  autoExpandParent: boolean;
  checkedKeys: CheckedKeys,
  selectedKeys: React.Key[];
  checkInit: boolean;
}

/**
 * 一颗空树
 */
const EMPTY_TREE: DataNode[] = [];

export default class GrantAuthModal extends React.PureComponent<GrantAuthProps<AuthTreeData>, GrantAuthState> {

  // formRef = React.createRef<FormInstance>();

  state: GrantAuthState = {
    expandedKeys: [],
    autoExpandParent: true,
    checkedKeys: [],
    selectedKeys: [],
    // 是否通过勾选动作取消全部勾选
    checkInit: false,
  };

  componentDidMount() {
    console.info('GrantAuthModal.componentDidMount');
  }

  componentWillUnmount() {
    console.info('GrantAuthModal.componentWillUnmount');
    this.setState({
      expandedKeys: [],
      autoExpandParent: true,
      checkedKeys: [],
      selectedKeys: [],
    });
  }

  onOk = () => {
    const { formData } = this.props;
    const { roleId, menuTree } = formData;
    const { checkedKeys } = this.state;
    // 需要遍历选中的节点，若其父节点不在列表中，则需要将父节点添加进来
    let grantKeys: React.Key[] = [];
    if (checkedKeys && checkedKeys instanceof Array) {
      // 先将权限树转换成List结构，依次遍历节点，用
      const treeNodeList = this.memoizeOneMenuTree2Array(menuTree);
      checkedKeys.forEach((checkNodeKey: React.Key) => {
        // 避免重复添加
        if (grantKeys.indexOf(checkNodeKey) === -1) {
          grantKeys.push(checkNodeKey);
        }
        // 参数1，选中的节点
        // 参数2，全部树节点
        // 寻找父节点，直至根节点
        const findParentNode = (checkNodeKey: React.Key, treeNodeList: MenuTreeItem[]) => {
          treeNodeList.forEach(treeNode => {
            const { key, parentId } = treeNode;
            // 判断其父节点在不在
            // 找到选中节点的父节点
            // 判断父节点是否选中，是否已添加到选中列表中
            // 若没有选中，且没有添加到选中列表中，则添加到选中列表中
            if (key === checkNodeKey && checkedKeys.indexOf(parentId) === -1 && grantKeys.indexOf(parentId) === -1) {
              if (parentId === '-1') {
                return;
              }
              grantKeys.push(parentId);
              // 父节点作为选中节点，寻找其父节点
              findParentNode(parentId, treeNodeList);
            }
          });
        };
        findParentNode(checkNodeKey, treeNodeList);
      });
    }
    const { onHandlerOK } = this.props;
    if (onHandlerOK) {
      const submitData = {
        roleId,
        menuIds: [...grantKeys]
      }
      onHandlerOK({
        ...submitData
      });
    }
  };

  onCancel = () => {
    // 先清除form表单
    // this.formRef.current!.resetFields();
    const {onHandlerCancel} = this.props;
    if (onHandlerCancel) {
      onHandlerCancel();
    }
  }

  afterClose = () => {
    console.info('afterClose');
    this.setState({
      expandedKeys: [],
      autoExpandParent: true,
      checkedKeys: [],
      selectedKeys: [],
      checkInit: false,
    });
  }

  onExpand: TreeProps['onExpand'] = (expandedKeys: React.Key[]) => {
    console.log('onExpand', expandedKeys);
    // if not set autoExpandParent to false, if children expanded, parent can not collapse.
    // or, you can remove all expanded children keys.
    this.setState({
      expandedKeys,
      autoExpandParent: false,
    });
  };

  onCheck: TreeProps['onCheck'] = (checkedKeys) => {
    console.log('onCheck', checkedKeys);
    let checkInit = false;
    if (checkedKeys && checkedKeys instanceof Array && checkedKeys.length == 0) {
      checkInit = true;
    }
    this.setState({
      checkedKeys,
      checkInit
    });
  };

  onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
    console.log('onSelect', info);
    console.log('onSelect', selectedKeys);
    this.setState({ selectedKeys });
  };

  /**
   * 将权限树转换为List，所有节点取出来，平级放到数组中
   * @param menuTree 权限树节点集合，集合的第一层为各页面节点
   */
  menuTree2Array = (menuTree: MenuTreeItem[]) => {
    console.info('menuTree2Array');
    const treeNodeList: MenuTreeItem[] = [];
    const treeDataTransform0 = (data: MenuTreeItem[]) => {
      data.forEach(item => {
        if (item.children) {
          treeDataTransform0(item.children);
        }
        treeNodeList.push(item);
      });
    };
    treeDataTransform0(menuTree);
    return treeNodeList;
  }

  /**
   * 权限树转换为List 缓存方法，当参数不变时，结果即不变
   */
  memoizeOneMenuTree2Array = memoizeOne(this.menuTree2Array, isEqual);

  /**
   * 处理已勾选节点的问题
   * <li>如果 父页面传进来的 grantKeys 有值，表示该角色已分配权限，则不看 state 中的 checkedKeys</li>
   * <li>如果 grantKeys 没有值，则看 state 中的 checkedKeys</li>
   * @returns 最后得到的勾选节点集合
   */
  getCheckedKeys = () => {
    const { checkedKeys, checkInit } = this.state;
    const { formData } = this.props;
    const { menuTree = [], grantKeys } = formData;
    // 权限树转换成平铺节点，这样好遍历
    const treeNodeList = this.memoizeOneMenuTree2Array(menuTree);
    let tmpCheckedKeys: CheckedKeys = [];
    // 优先看 checkedKeys
    if (checkedKeys && checkedKeys instanceof Array && checkedKeys.length > 0) {
      tmpCheckedKeys = [...checkedKeys];
    } else if (grantKeys && grantKeys.length > 0) {
      if (checkInit && checkedKeys instanceof Array) {
        tmpCheckedKeys = [...checkedKeys];
      } else {
        // 寻找已勾选节点的父节点
        grantKeys.forEach((checkNode: GrantKey) => {
          treeNodeList.forEach(node => {
            const { id } = checkNode;
            const { key, children } = node;
            if (key === id && !children) {
              // 不存在子节点的才加进来
              (tmpCheckedKeys as Array<React.Key>).push(id);
            }
          });
        });
      }
      // 若子节点全部存在，则父节点会自动勾选
    }
    return tmpCheckedKeys;
  }

  transformTreeData = (menuTree: MenuTreeItem[]): DataNode[] => {
    if (!menuTree) {
      return EMPTY_TREE;
    }
    return menuTree.map((item: MenuTreeItem) => {
      const { key, title } = item;
      const node: DataNode = {
        key,
        title
      }
      if (item.children) {
        node.children = this.transformTreeData(item.children);
      }
      return node;
    });
  }

  render() {
    console.info("GrantAuthModal.render");
    const { expandedKeys, selectedKeys, autoExpandParent } = this.state;
    const { formData, modalWidth, modalVisible, modalTitle, loading } = this.props;
    const { menuTree = [] } = formData;
    // 处理已勾选节点的问题
    const tmpCheckedKeys: CheckedKeys = this.getCheckedKeys();
    const treeData = this.transformTreeData(menuTree);
    console.info(treeData);

    return (
      <Modal
        title={modalTitle}
        destroyOnClose
        maskClosable={false}
        width={modalWidth}
        open={modalVisible}
        confirmLoading={loading}
        onOk={this.onOk}
        onCancel={this.onCancel}
        afterClose={this.afterClose}>
          <Tree
            checkable
            showLine
            onExpand={this.onExpand}
            expandedKeys={expandedKeys}
            autoExpandParent={autoExpandParent}
            onCheck={this.onCheck}
            checkedKeys={tmpCheckedKeys}
            onSelect={this.onSelect}
            selectedKeys={selectedKeys}
            treeData={treeData}
          />
      </Modal>
    );
  }
}